package com.icw.utility;

import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.ClassUtils;

public class ClassUtil {

	private static String PACKAGE_PLACE = "/\\*";

	private static String PACKAGE_PLACES = "/\\*\\*";

	private static String PACKAGE_PIECE = "/([a-zA-Z]|[0-9]|_)+";

	private static String PACKAGE_PIECES = String.format("(%s)+", PACKAGE_PIECE);

	private static Map<String, Set<Class<?>>> classCache = new ConcurrentHashMap<>();

	public static Set<Class<?>> getClasses(String pack) throws Exception {
		Set<Class<?>> res;
		if ((res = classCache.get(pack)) == null) {
			synchronized ("CLASS_SET_" + pack) {
				if ((res = classCache.get(pack)) == null) {
					Set<Class<?>> classSet = new LinkedHashSet<>();
					String resolvedPackage = ClassUtils.convertClassNameToResourcePath(pack);
					String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolvedPackage + '/' + "*.class";
					String resolvedRegExp = resolvedPackage.replaceAll(PACKAGE_PLACES, PACKAGE_PIECES).replaceAll(PACKAGE_PLACE, PACKAGE_PIECE) + PACKAGE_PIECE;
					Pattern pattern = Pattern.compile(resolvedRegExp);
					for (Resource temp : new PathMatchingResourcePatternResolver().getResources(packageSearchPath)) {
						String classLocation = temp.getURI().toString();
						Matcher matcher = pattern.matcher(classLocation);
						String classPath = null;
						while (matcher.find()) {
							classPath = matcher.group();
						}
						if (classPath != null) {
							classSet.add(Class.forName(classPath.replaceAll("/", ".")));
						}
					}
					classCache.put(pack, res = classSet);
				}
			}
		}
		return res;
	}
}